package cn.ryh.netty.nio;

import java.nio.ByteBuffer;
/**
 * buffer 示例
 * @author Raoyh
 */
public class BufferDemo {
    /**
     * 缓存区：
     *     一个用于特定基本数据类型的容器。由 java.nio 包定义的。
     *     Buffer 就像一个数组，可以保存多个相同类型的数据。
     *     通过 XxxBuffer.allocate(int capacity)创建一个容量为 capacity 的XxxBuffer 对象.
     *     例如 ByteBuffer b = ByteBuffer.allocate(2048);
     *
     *     容量（capacity）：表示Buffer最大数据容量，缓存区容量不能为负即capacity不能为负、且创建后不能更改。
     *
     *     限制（limit）:第一个不应该读取或写入的数据索引，即位于limit后的数据不可读写。limit不能为负且不能大于其容量。
     *
     *     位置（position）：下一个要读取或写入的数据的索引。position不能为负，并且不能大于其限制(limit)
     *
     *     标记 (mark)与重置 (reset)： 标记是一个索引，通过 Buffer 中的 mark() 方法指定 Buffer
     *         中一个特定的 position，之后可以通过调用 reset() 方法恢复到这个 position.
     *
     *     标记、 位置、 限制、 容量遵守以下不变式： 0 <= mark <= position <= limit <= capacity
     *
     *     缓冲区的数据操作:Buffer 所有子类提供了两个用于数据操作的方法： get()与 put()方法
     *         > 获取 Buffer 中的数据
     *         get() ：读取单个字节
     *         get(byte[] dst)：批量读取多个字节到 dst 中
     *         get(int index)：读取指定索引位置的字节(不会移动 position)
     *         >放入数据到 Buffer 中
     *         put(byte b)：将给定单个字节写入缓冲区的当前位置
     *         put(byte[] src)：将 src 中的字节写入缓冲区的当前位置
     *         put(int index, byte b)：将指定字节写入缓冲区的索引位置(不会移动 position)
     * @param args
     */
    public static void main(String[] args) {
        BufferDemo bufferDemo = new BufferDemo();
        bufferDemo.test1();
        bufferDemo.test2();
        bufferDemo.test3();
    }
    public void test1() {
        String str = "abcde";
        //1.分配一个指定大小的缓冲区
        ByteBuffer buf = ByteBuffer.allocate(1024);
        System.out.println(buf.position());
        System.out.println(buf.limit());
        System.out.println(buf.capacity());
        System.out.println("1=============================");

        //2.存入数据到缓冲区中
        buf.put(str.getBytes());
        System.out.println(buf.position());
        System.out.println(buf.limit());
        System.out.println(buf.capacity());
        System.out.println("2=============================");

        //3.切换为读取数据模式
        buf.flip();
        System.out.println(buf.position());
        System.out.println(buf.limit());
        System.out.println(buf.capacity());
        System.out.println("3=============================");

        //4.读取缓冲区中的数据
        byte[] dst = new byte[buf.limit()];
        buf.get(dst);
        System.out.println(new String(dst, 0, dst.length));
        System.out.println(buf.position());
        System.out.println(buf.limit());
        System.out.println(buf.capacity());
        System.out.println("4=============================");

        //5.可重复读
        buf.rewind();
        //System.out.println((char)buf.get());
        System.out.println(buf.position());
        System.out.println(buf.limit());
        System.out.println(buf.capacity());
        System.out.println("5=============================");

        //6.清空缓冲区,但缓冲区中的数据依然存在,只是处于"被遗忘"状态
        buf.clear();
        //System.out.println((char)buf.get());
        System.out.println(buf.position());
        System.out.println(buf.limit());
        System.out.println(buf.capacity());
    }
        public void test2(){
        String str = "abcde";
        ByteBuffer buf = ByteBuffer.allocate(1024);
        buf.put(str.getBytes());
        buf.flip();
        byte[] dst = new byte[buf.limit()];
        buf.get(dst,0,2);
        System.out.println(new String(dst,0,2));
        System.out.println(buf.position());

        System.out.println("========================");
        buf.mark();
        buf.get(dst,0,2);
        System.out.println(new String(dst,0,2));
        System.out.println(buf.position());

        System.out.println("========================");
        buf.reset();//恢复到mark的位置
        System.out.println(buf.position());

        System.out.println("========================");
        //判断缓冲区中是否还有剩余数据
        if (buf.hasRemaining()){
            //获取缓冲区中可以操作的数量
            System.out.println(buf.remaining());
        }

        while (buf.hasRemaining()){
            byte b = buf.get();
            System.out.println((char) b);
        }
    }

    public void test3(){
        /**
         * 非直接缓冲区：通过 allocate() 方法分配缓冲区，将缓冲区建立在 JVM 的内存中
         * 直接缓冲区：通过 allocateDirect() 方法分配直接缓冲区，将缓冲区建立在物理内存中。可以提高效率
         */
        //分配直接缓冲区
        ByteBuffer buf = ByteBuffer.allocateDirect(1024);
        //判断是否为直接缓冲区
        System.out.println(buf.isDirect());
    }
}

